{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. 类的创建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2318640183688\n",
      "<class 'type'>\n",
      "<class '__main__.Student'>\n"
     ]
    }
   ],
   "source": [
    "class Student:  # Student为类名，由一个或者多个单词组成，要求每个单词首字母大写，其余小写\n",
    "    native_place = '吉林'  # 直接写在类中的变量，称为类属性\n",
    "\n",
    "    # 初始化方法\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name  # self.name为实例属性，进行了赋值操作，将局部变量name的值赋值给实体属性\n",
    "        self.age = age\n",
    "\n",
    "    # 实例方法（在类之外定义的是函数，在类之内定义的是方法）\n",
    "    def eat(self):\n",
    "        print('学生在吃饭')\n",
    "\n",
    "    # 静态方法\n",
    "    @staticmethod\n",
    "    def method():  # 不写self\n",
    "        print('我使用了静态方法')\n",
    "\n",
    "    # 类方法\n",
    "    @classmethod\n",
    "    def cm(cls):\n",
    "        print('我使用了类方法')\n",
    "\n",
    "\n",
    "# python中一切皆对象，student是对象吗？有开空间吗\n",
    "print(id(Student))\n",
    "print(type(Student))\n",
    "print(Student)\n",
    "\n",
    "\n",
    "# 函数\n",
    "def drink():\n",
    "    print('喝水')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. 对象的创建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2318654671952\n",
      "<class '__main__.Student'>\n",
      "<__main__.Student object at 0x0000021BDA968C50>\n",
      "------------\n",
      "2318640201624\n",
      "<class 'type'>\n",
      "<class '__main__.Student'>\n",
      "学生在吃饭\n",
      "jack\n",
      "20\n",
      "学生在吃饭\n"
     ]
    }
   ],
   "source": [
    "class Student:  # Student为类名，由一个或者多个单词组成，要求每个单词首字母大写，其余小写\n",
    "    native_place = '吉林'  # 直接写在类中的变量，称为类属性\n",
    "\n",
    "    # 初始化方法\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name  # self.name为实例属性，进行了赋值操作，将局部变量name的值赋值给实体属性\n",
    "        self.age = age\n",
    "\n",
    "    # 实例方法（在类之外定义的是函数，在类之内定义的是方法）\n",
    "    def eat(self):\n",
    "        print('学生在吃饭')\n",
    "\n",
    "    # 静态方法\n",
    "    @staticmethod\n",
    "    def method():  # 不写self\n",
    "        print('我使用了静态方法')\n",
    "\n",
    "    # 类方法\n",
    "    @classmethod\n",
    "    def cm(cls):\n",
    "        print('我使用了类方法')\n",
    "\n",
    "\n",
    "stu1 = Student('jack', 20)\n",
    "print(id(stu1))  # 实例对象\n",
    "print(type(stu1))\n",
    "print(stu1)\n",
    "print('------------')\n",
    "print(id(Student))  # 类对象\n",
    "print(type(Student))\n",
    "print(Student)\n",
    "\n",
    "# 调用实例对象的方法\n",
    "stu1.eat()  # 对象名.方法名()\n",
    "print(stu1.name)\n",
    "print(stu1.age)\n",
    "\n",
    "# 类名.方法名(类的对象)-->实际上就是方法定义处的self\n",
    "Student.eat(stu1)  # 与36行代码功能相同，都是调用Student中的eat方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. 类属性、类方法、静态方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "吉林\n",
      "吉林\n",
      "吉林\n",
      "天津\n",
      "天津\n",
      "我使用了类方法\n",
      "我使用了静态方法\n"
     ]
    }
   ],
   "source": [
    "class Student:  # Student为类名，由一个或者多个单词组成，要求每个单词首字母大写，其余小写\n",
    "    native_place = '吉林'  # 直接写在类中的变量，称为类属性\n",
    "\n",
    "    # 初始化方法\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name  # self.name为实例属性，进行了赋值操作，将局部变量name的值赋值给实体属性\n",
    "        self.age = age\n",
    "\n",
    "    # 实例方法（在类之外定义的是函数，在类之内定义的是方法）\n",
    "    def eat(self):\n",
    "        print('学生在吃饭')\n",
    "\n",
    "    # 静态方法\n",
    "    @staticmethod\n",
    "    def method():  # 不写self\n",
    "        print('我使用了静态方法')\n",
    "\n",
    "    # 类方法\n",
    "    @classmethod\n",
    "    def cm(cls):\n",
    "        print('我使用了类方法')\n",
    "\n",
    "\n",
    "# 类属性的使用方式\n",
    "print(Student.native_place)\n",
    "stu1 = Student('张三', 20)\n",
    "stu2 = Student('李四', 30)\n",
    "print(stu1.native_place)\n",
    "print(stu2.native_place)\n",
    "\n",
    "Student.native_place = '天津'\n",
    "print(stu1.native_place)\n",
    "print(stu2.native_place)\n",
    "\n",
    "# 类方法的使用方式\n",
    "Student.cm()\n",
    "\n",
    "# 静态方法的使用方式\n",
    "Student.method()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4. 动态绑定属性和方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2318654792368\n",
      "2318654792424\n",
      "张三 20\n",
      "李四 30 女\n",
      "张三在吃饭\n",
      "李四在吃饭\n",
      "定义在类之外的，称为函数\n"
     ]
    }
   ],
   "source": [
    "class Student:\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "    def eat(self):\n",
    "        print(self.name + '在吃饭')\n",
    "\n",
    "\n",
    "stu1 = Student('张三', 20)\n",
    "stu2 = Student('李四', 30)\n",
    "print(id(stu1))\n",
    "print(id(stu2))\n",
    "\n",
    "\n",
    "# 动态绑定性别属性\n",
    "stu2.gender = '女'\n",
    "print(stu1.name, stu1.age)  # stu1没有\n",
    "print(stu2.name, stu2.age, stu2.gender)\n",
    "\n",
    "\n",
    "# 使用类中的方法\n",
    "stu1.eat()\n",
    "stu2.eat()\n",
    "\n",
    "\n",
    "# 动态绑定方法\n",
    "def show():\n",
    "    print('定义在类之外的，称为函数')\n",
    "\n",
    "\n",
    "stu1.show = show\n",
    "stu1.show()\n",
    "\n",
    "\n",
    "# stu2.show()  # TypeError: 'NoneType' object is not callable  未绑定"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5. 封装"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "汽车已经启动\n",
      "宝马\n",
      "张三 20\n",
      "张三\n",
      "['_Student__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'show']\n",
      "20\n"
     ]
    }
   ],
   "source": [
    "class Car:\n",
    "    def __init__(self, brand):\n",
    "        self.brand = brand\n",
    "\n",
    "    def start(self):\n",
    "        print('汽车已经启动')\n",
    "\n",
    "\n",
    "car = Car('宝马')\n",
    "car.start()\n",
    "print(car.brand)\n",
    "\n",
    "\n",
    "class Student:\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.__age = age  # age不希望在类的外部使用，所以加了两个__\n",
    "\n",
    "    def show(self):\n",
    "        print(self.name, self.__age)\n",
    "\n",
    "\n",
    "stu = Student('张三', 20)\n",
    "stu.show()\n",
    "# 在类的外部使用name与age\n",
    "print(stu.name)\n",
    "# print(stu.__age)  # AttributeError\n",
    "# 怎么在外部使用age\n",
    "print(dir(stu))  # 打印出来再找\n",
    "print(stu._Student__age)  # 在类的外部可以通过_Student__age进行访问"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 6. 继承"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "张三 20\n",
      "李四 34\n"
     ]
    }
   ],
   "source": [
    "class Person(object):\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "    def info(self):\n",
    "        print(self.name, self.age)\n",
    "\n",
    "\n",
    "class Student(Person):\n",
    "    def __init__(self, name, age, stu_no):\n",
    "        super().__init__(name, age)\n",
    "        self.stu_no = stu_no\n",
    "\n",
    "\n",
    "class Teacher(Person):\n",
    "    def __init__(self, name, age, teach_year):\n",
    "        super().__init__(name, age)\n",
    "        self.teach_year = teach_year\n",
    "\n",
    "\n",
    "stu = Student('张三', 20, '1001')\n",
    "teacher = Teacher('李四', 34, 10)\n",
    "\n",
    "stu.info()\n",
    "teacher.info()\n",
    "\n",
    "\n",
    "# 多继承\n",
    "class A(object):\n",
    "    pass\n",
    "\n",
    "\n",
    "class B(object):\n",
    "    pass\n",
    "\n",
    "\n",
    "class C(B, A):  # 两个父类，多继承\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 7. 方法重写"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "张三 20\n",
      "1001\n",
      "李四 34\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "class Person(object):\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "    def info(self):\n",
    "        print(self.name, self.age)\n",
    "\n",
    "\n",
    "class Student(Person):\n",
    "    def __init__(self, name, age, stu_no):\n",
    "        super().__init__(name, age)\n",
    "        self.stu_no = stu_no\n",
    "\n",
    "    def info(self):\n",
    "        super().info()\n",
    "        print(self.stu_no)\n",
    "\n",
    "\n",
    "class Teacher(Person):\n",
    "    def __init__(self, name, age, teach_year):\n",
    "        super().__init__(name, age)\n",
    "        self.teach_year = teach_year\n",
    "\n",
    "    def info(self):\n",
    "        super().info()\n",
    "        print(self.teach_year)\n",
    "\n",
    "\n",
    "stu = Student('张三', 20, '1001')\n",
    "teacher = Teacher('李四', 34, 10)\n",
    "\n",
    "stu.info()\n",
    "teacher.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 8. object类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']\n",
      "我的名字是张三，今年20岁\n",
      "<class '__main__.Student'>\n"
     ]
    }
   ],
   "source": [
    "class Student:  # 默认继承object类\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "    def __str__(self):\n",
    "        return '我的名字是{0}，今年{1}岁'.format(self.name, self.age)\n",
    "\n",
    "\n",
    "stu = Student('张三', 20)\n",
    "print(dir(stu))\n",
    "print(stu)  # 不输出内存地址了，默认调用__str__方法\n",
    "print(type(stu))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 9. 多态"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "猫吃鱼\n",
      "狗吃肉\n",
      "动物会吃\n",
      "人吃五谷杂粮\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'、\\n静态语言和动态语言关于多态的区别\\n继承\\n方法重写\\n父类引用指向子类对象\\n'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class Animal(object):\n",
    "    def eat(self):\n",
    "        print('动物会吃')\n",
    "\n",
    "\n",
    "class Dog(Animal):\n",
    "    def eat(self):\n",
    "        print('狗吃肉')\n",
    "\n",
    "\n",
    "class Cat(Animal):\n",
    "    def eat(self):\n",
    "        print('猫吃鱼')\n",
    "\n",
    "\n",
    "class Person(object):\n",
    "    def eat(self):\n",
    "        print('人吃五谷杂粮')\n",
    "\n",
    "\n",
    "def fun(obj):\n",
    "    obj.eat()\n",
    "\n",
    "\n",
    "fun(Cat())\n",
    "fun(Dog())\n",
    "fun(Animal())\n",
    "# 不存在继承关系，只关心对象的行为，不关心对象是什么类型\n",
    "fun(Person())\n",
    "\n",
    "\"\"\"、\n",
    "静态语言和动态语言关于多态的区别\n",
    "继承\n",
    "方法重写\n",
    "父类引用指向子类对象\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 10. 特殊属性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'name': 'Jack', 'age': 20}\n",
      "{'__module__': '__main__', '__init__': <function C.__init__ at 0x0000021BDA5E6AE8>, '__doc__': None}\n",
      "<class '__main__.C'>\n",
      "(<class '__main__.A'>, <class '__main__.B'>)\n",
      "<class '__main__.A'>\n",
      "(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)\n",
      "[<class '__main__.C'>]\n"
     ]
    }
   ],
   "source": [
    "# print(dir(object))\n",
    "class A:\n",
    "    pass\n",
    "\n",
    "\n",
    "class B:\n",
    "    pass\n",
    "\n",
    "\n",
    "class C(A, B):\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "\n",
    "x = C('Jack', 20)  # x是C的实例对象\n",
    "print(x.__dict__)  # 以字典的形式展示实例对象的属性和值\n",
    "print(C.__dict__)  # 以字典的形式，展示类对象的属性和方法字典\n",
    "print(x.__class__)  # 输出实例对象所属的类型  <class '__main__.C'>\n",
    "print(C.__bases__)  # 输出类对象的父类类型的元组  (<class '__main__.A'>, <class '__main__.B'>)\n",
    "print(C.__base__)  # 输出最近一个父类（基类）\n",
    "print(C.__mro__)  # 类的层次结构 (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)\n",
    "print(A.__subclasses__())  # 子类列表，输出类对象的子类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 11. 特殊方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "120\n",
      "120\n",
      "JackMike\n",
      "JackMike\n",
      "4\n",
      "4\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "a = 20\n",
    "b = 100\n",
    "c = a + b  # 两个整数类型的相加操作\n",
    "d = a.__add__(b)\n",
    "\n",
    "print(c)\n",
    "print(d)\n",
    "\n",
    "\n",
    "class Student:\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def __add__(self, other):\n",
    "        return self.name + other.name\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.name)\n",
    "\n",
    "\n",
    "stu1 = Student('Jack')\n",
    "stu2 = Student('Mike')\n",
    "\n",
    "print(stu1 + stu2)  # 实现了两个对象的加法运算，因为在类中编写了__add__()特殊方法\n",
    "\n",
    "s = stu1.__add__(stu2)\n",
    "print(s)  # 同上\n",
    "\n",
    "# __len__()\n",
    "lst = [11, 22, 33, 44]\n",
    "print(len(lst))  # len是内置函数len\n",
    "print(lst.__len__())  # 同上\n",
    "\n",
    "print(len(stu1))  # __len__()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 12. new和init"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "object这个类对象的id为：1652798848\n",
      "Person这个类对象的id为：2318640220504\n",
      "__new__被调用执行了，cls的id值为2318640220504\n",
      "创建的对象的id为2318654629704\n",
      "__init__被调用执行了，self的id值为2318654629704\n",
      "p1这个Person类的实例对象的id为：2318654629704\n"
     ]
    }
   ],
   "source": [
    "class Person:\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        print('__new__被调用执行了，cls的id值为{0}'.format(id(cls)))\n",
    "        obj = super().__new__(cls)\n",
    "        print('创建的对象的id为{0}'.format(id(obj)))\n",
    "        return obj\n",
    "\n",
    "    def __init__(self, name, age):\n",
    "        print('__init__被调用执行了，self的id值为{0}'.format(id(self)))\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "\n",
    "print('object这个类对象的id为：{0}'.format(id(object)))\n",
    "print('Person这个类对象的id为：{0}'.format(id(Person)))\n",
    "\n",
    "# 创建Person类的实例对象\n",
    "p1 = Person('张三', 20)\n",
    "print('p1这个Person类的实例对象的id为：{0}'.format(id(p1)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 13. 类的赋值与浅深拷贝"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.CPU object at 0x0000021BDA99E4E0> 2318654891232\n",
      "<__main__.CPU object at 0x0000021BDA99E4E0> 2318654891232\n",
      "<__main__.Computer object at 0x0000021BDA99E438> <__main__.CPU object at 0x0000021BDA99E4E0> <__main__.Disk object at 0x0000021BDA99E668>\n",
      "<__main__.Computer object at 0x0000021BDA99E550> <__main__.CPU object at 0x0000021BDA99E4E0> <__main__.Disk object at 0x0000021BDA99E668>\n",
      "<__main__.Computer object at 0x0000021BDA99E438> <__main__.CPU object at 0x0000021BDA99E4E0> <__main__.Disk object at 0x0000021BDA99E668>\n",
      "<__main__.Computer object at 0x0000021BDA99E7B8> <__main__.CPU object at 0x0000021BDA99E748> <__main__.Disk object at 0x0000021BDA99E828>\n"
     ]
    }
   ],
   "source": [
    "class CPU:\n",
    "    pass\n",
    "\n",
    "\n",
    "class Disk:\n",
    "    pass\n",
    "\n",
    "\n",
    "class Computer:\n",
    "    def __init__(self, cpu, disk):\n",
    "        self.cpu = cpu\n",
    "        self.disk = disk\n",
    "\n",
    "\n",
    "# 变量的赋值\n",
    "cpu1 = CPU()\n",
    "cpu2 = cpu1\n",
    "print(cpu1, id(cpu1))\n",
    "print(cpu2, id(cpu2))  # 内存地址相同，同一个对象，放到两个地址中存储，形成两个变量\n",
    "\n",
    "# 浅拷贝：一般都是浅拷贝，拷贝时，对象包含的子对象内容不拷贝，因此源对象与拷贝对象会引用同一个子对象\n",
    "disk1 = Disk()\n",
    "computer = Computer(cpu1, disk1)\n",
    "\n",
    "import copy\n",
    "computer2 = copy.copy(computer)\n",
    "print(computer, computer.cpu, computer.disk)\n",
    "print(computer2, computer2.cpu, computer2.disk)\n",
    "\n",
    "# 深拷贝：使用copy模块的deepcopy函数，递归拷贝对象中包含的子对象，源对象和拷贝对象所有的子对象也不相同\n",
    "computer3 = copy.deepcopy(computer)\n",
    "print(computer, computer.cpu, computer.disk)\n",
    "print(computer3, computer3.cpu, computer3.disk)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.6.3",
   "language": "python",
   "name": "python3.6.3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "480px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
